package metaLoader

import (
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	backenddb "github.com/sniperHW/fly/backend/db"
	"github.com/sniperHW/fly/proto"
	"strings"
)

func pgsqlOpen(host string, port int, dbname string, user string, password string) (*sqlx.DB, error) {
	connStr := fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=disable", host, port, dbname, user, password)
	return sqlx.Open("postgres", connStr)
}

func mysqlOpen(host string, port int, dbname string, user string, password string) (*sqlx.DB, error) {
	connStr := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, password, host, port, dbname)
	return sqlx.Open("mysql", connStr)
}

func sqlOpen(sqlType string, host string, port int, dbname string, user string, password string) (*sqlx.DB, error) {
	if sqlType == "mysql" {
		return mysqlOpen(host, port, dbname, user, password)
	} else {
		return pgsqlOpen(host, port, dbname, user, password)
	}
}

func LoadDBMetaFromSqlJson(sqlType string, host string, port int, dbname string, user string, password string) (*backenddb.DbDef, error) {
	var db *sqlx.DB
	var err error
	var def *backenddb.DbDef

	db, err = sqlOpen(sqlType, host, port, dbname, user, password)

	if nil != err {
		return nil, err
	} else {

		rows, err := db.Query("select dbmeta from dbmeta")

		if nil != err {
			return nil, err
		}
		defer rows.Close()

		var meta string

		if rows.Next() {
			err := rows.Scan(&meta)
			if nil != err {
				return nil, err
			}
		}

		def, err = backenddb.CreateDbDefFromJsonString([]byte(meta))
		return def, err
	}
}

/*
 * 格式:field1:type:default,field2:type:default,...
 * 例如name:string:,age:int:,phone:string:
 */
func parseFields(s string) ([]backenddb.FieldDef, error) {
	var fields []backenddb.FieldDef
	f := strings.Split(s, ",")
	for _, v := range f {
		if v != "" {
			field := strings.Split(v, ":")

			if len(field) != 3 {
				return nil, fmt.Errorf("len(fields) != 3")
			}

			name := field[0]

			//字段名不允许以__开头
			if strings.HasPrefix(name, "__") {
				return nil, fmt.Errorf("has prefix _")
			}

			ftype := backenddb.GetTypeByStr(field[1])

			if ftype == proto.ValueType_invaild {
				return nil, errors.New("unsupport data type")
			}

			fields = append(fields, backenddb.FieldDef{
				Name:        name,
				Type:        field[1],
				DefautValue: field[2],
			})
		}
	}
	return fields, nil
}

//旧版兼容模式，每个表一行定义
func LoadDBMetaFromSqlOld(sqlType string, host string, port int, dbname string, user string, password string) (*backenddb.DbDef, error) {
	var db *sqlx.DB
	var err error
	var def backenddb.DbDef

	db, err = sqlOpen(sqlType, host, port, dbname, user, password)
	if nil != err {
		return nil, err
	} else {

		rows, err := db.Query("select __table__,__conf__ from table_conf")

		if nil != err {
			return nil, err
		}
		defer rows.Close()

		for rows.Next() {
			var __table__ string
			var __conf__ string

			err := rows.Scan(&__table__, &__conf__)

			if nil != err {
				return nil, err
			}

			fields, err := parseFields(__conf__)
			if nil != err {
				return nil, err
			} else {
				tab := backenddb.TableDef{
					Name:   __table__,
					Fields: fields,
				}

				def.TableDefs = append(def.TableDefs, tab)
			}
		}

		return &def, nil
	}

}
